//
//  main.cpp
//
//
//  Created by Kun Zhao on 12/12/05.
//  Copyright (c) 2012 Kyoto University. All rights reserved.
//

#include <iostream>
#include <kvs/glut/Application>
#include <kvs/glut/Screen>
#include <kvs/StructuredVolumeObject>
#include <kvs/StructuredVolumeImporter>
#include <kvs/HydrogenVolumeData>
#include <kvs/CommandLine>
#include "RayCastingRenderer.h"
#include "TransferFunction3D.h"

class Argument : public kvs::CommandLine
{
public:
    
    //std::string directory;
    std::string filename_s;
    std::string filename_rhoo;
    std::string filename_velocity;
    std::string filename_tfunc;
    float s_min;
    float s_max;
    int Threshold;
    
    Argument( int argc, char** argv ) : CommandLine( argc, argv )
    {
        add_help_option();
        //addOption( "d", "directory name of the data", 1, true );
        addOption( "s", "filename of salinity", 1, true );
        addOption( "r", "filename of rhoo", 1, true );
        addOption( "v", "filename of velocity", 1, true );
        addOption( "t", "output filename for the transfer function", 1, false );
        addOption( "a", "left of OW tfunc", 1, false );
        addOption( "b", "right of OW tfunc", 1, false );
        addOption( "TEST", "test for the transfer function: use the same assigned TF for five times", 0, false );
        addOption( "T", "set the threshold for the ensemble rendering", 1, true );
    }
    
    void exec()
    {
        if( !this->parse() ) exit( EXIT_FAILURE );
        //if( this->hasOption( "d" ) ) directory = this->optionValue<std::string>( "d" );
        if( this->hasOption( "s" ) ) filename_s = this->optionValue<std::string>( "s" );
        if( this->hasOption( "r" ) ) filename_rhoo = this->optionValue<std::string>( "r" );
        if( this->hasOption( "v" ) ) filename_velocity = this->optionValue<std::string>( "v" );
        if( this->hasOption( "t" ) ) filename_tfunc = this->optionValue<std::string>( "t" );
        if( this->hasOption( "a" ) ) s_min = this->optionValue<float>( "a" );
        if( this->hasOption( "b" ) ) s_max = this->optionValue<float>( "b" );
        if( this->hasOption( "T" ) ) Threshold = this->optionValue<int>( "T" );
    }
};

int main( int argc, char** argv )
{
    kvs::glut::Application app( argc, argv );
    kvs::glut::Screen screen( &app );
    
    Argument param( argc, argv );
    param.exec();
    
    kvs::StructuredVolumeObject* volume_s = new kvs::StructuredVolumeImporter( param.filename_s);
    kvs::StructuredVolumeObject* volume_r = new kvs::StructuredVolumeImporter( param.filename_rhoo );
    kvs::StructuredVolumeObject* volume_v = new kvs::StructuredVolumeImporter( param.filename_velocity );
    volume_s->setMinMaxValues( 31.0, 35.0 );
    volume_v->setMinMaxValues( 0.0, 306.863 );
    std::cout << "finish loading data" << std::endl;
    
    //  // set the 3d transfer function
    if( param.hasOption( "TEST" ) )
    {
        kun::TransferFunction3D tfunc3d;
        size_t size = 40;
        size_t width = size;
        size_t height = size;
        size_t depth = size;
        tfunc3d.setResolution(kvs::Vector3f( width, height, depth) );
        float* tfunc3d_data = new float[width * height * depth * 4];
        float max_opacity = 1;
        for ( size_t k = 0; k < depth; k++ )
            for ( size_t j = 0; j < height; j++ )
                for ( size_t i = 0; i < width; i++ )
                {
                    int index = ( i + j * width + k * width * height ) * 4;
                    float opacity;
                    if ( k > 15 )
                        opacity = 1;
                    else
                        opacity = ((float)k / 15) * max_opacity;
                    
                    if ( param.s_min <= i && i <= param.s_max ) // blue
                    {
                        tfunc3d_data[index] = 0;      // red
                        tfunc3d_data[index + 1] = 0;  // green
                        tfunc3d_data[index + 2] = 1;  // blue
                        tfunc3d_data[index + 3] = opacity;
                    }
                    else
                    {
                        tfunc3d_data[index] = 0;      // red
                        tfunc3d_data[index + 1] = 0;  // green
                        tfunc3d_data[index + 2] = 1;  // blue
                        tfunc3d_data[index + 3] = 0;
                    }
                    
                }
        tfunc3d_data[0] = 1;
        tfunc3d_data[1] = 1;
        tfunc3d_data[2] = 1;
        tfunc3d_data[3] = 0.1;
        tfunc3d.setValues( tfunc3d_data );
        tfunc3d.write( param.filename_tfunc );
    }
    
    // import the five transfer functions
    kun::TransferFunction3D tfunc3d1;
    kun::TransferFunction3D tfunc3d2;
    kun::TransferFunction3D tfunc3d3;
    kun::TransferFunction3D tfunc3d4;
    kun::TransferFunction3D tfunc3d5;
    
    if( param.hasOption( "TEST" ) )
    {
        tfunc3d1.import( param.filename_tfunc );
        tfunc3d2.import( param.filename_tfunc );
        tfunc3d3.import( param.filename_tfunc );
        tfunc3d4.import( param.filename_tfunc );
        tfunc3d5.import( param.filename_tfunc );
    }
    else
    {
        tfunc3d1.import( "OW1.tfunc3d" );
        tfunc3d2.import( "OW2.tfunc3d" );
        tfunc3d3.import( "OW3.tfunc3d" );
        tfunc3d4.import( "OW4.tfunc3d" );
        tfunc3d5.import( "OW5.tfunc3d" );
    }
    
    kun::RayCastingRenderer* renderer = new kun::RayCastingRenderer();
    
    renderer->addVolume2( volume_r );
    renderer->addVolume3( volume_v );
    renderer->set3DTransferFunction1( tfunc3d1 );
    renderer->set3DTransferFunction2( tfunc3d2 );
    renderer->set3DTransferFunction3( tfunc3d3 );
    renderer->set3DTransferFunction4( tfunc3d4 );
    renderer->set3DTransferFunction5( tfunc3d5 );
    renderer->setThreshold( param.Threshold );
    
    // set the land object
    kvs::StructuredVolumeObject* volume_land = new kvs::StructuredVolumeImporter( "../Preprocess/land/ref.kvsml" );
    renderer->setLand( volume_land );
    
    //renderer->disableShading();
    
    screen.registerObject( volume_s, renderer );
    //screen.background()->setColor( kvs::RGBColor(255, 255, 255) );
    screen.show();
    
    return( app.run() );
}
